﻿using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Diagnostics;
using System;
using System.Text;
using System.Linq;

namespace MyFinanceManager.Objects
{
    [Serializable]
    public class Database
    {
        #region Fields
        private static XmlSerializer xmlSer = null;
        private List<PostingRecord> expenses;
        private List<PostingRecord> earnings;
        private List<FuelRecord> fuels;
        private List<TransferRecord> transfers;
        private List<Account> accounts;
        private static string lastMileometer = string.Empty;
        private static List<string> namesOfAccounts = new List<string>();
        private static List<string> namesOfFuelstations = new List<string>();
        private static List<string> namesOfCategoriesEx = new List<string>();
        private static List<string> namesOfCategoriesIn = new List<string>();
        #endregion

        #region Properties
        public List<PostingRecord> Expenses
        {
            get
            {
                if (this.expenses == null)
                    this.expenses = new List<PostingRecord>();
                return expenses;
            }
        }

        public List<PostingRecord> Earnings
        {
            get
            {
                if (this.earnings == null)
                    this.earnings = new List<PostingRecord>();
                return earnings;
            }
        }

        public List<FuelRecord> Fuels
        {
            get
            {
                if (this.fuels == null)
                    this.fuels = new List<FuelRecord>();
                return fuels;
            }
        }

        public List<TransferRecord> Transfers
        {
            get
            {
                if (this.transfers == null)
                    this.transfers = new List<TransferRecord>();
                return transfers;
            }
        }

        public List<Account> Accounts
        {
            get
            {
                if (this.accounts == null)
                    this.accounts = new List<Account>();
                return accounts;
            }
        }

        #region statics
        public static List<string> NamesOfAccounts
        {
            get
            {
                if (Database.namesOfAccounts.Count == 0)
                {
                    using (StreamReader fs = File.OpenText(Filenames.FilenameAccounts))
                    {
                        while (!fs.EndOfStream)
                        {
                            string line = fs.ReadLine().Trim();
                            if (!String.IsNullOrEmpty(line))
                                Database.namesOfAccounts.Add(line);
                        }
                    }
                }
                // if there were no items in the txt-File we need to get the accounts from the xml.
                // this will need some time, but it should be only neccessary by first usages
                if (Database.namesOfAccounts.Count == 0)
                {
                    return (from acc in Database.Db.Accounts
                            select acc.Name).ToList<string>();
                }

                return Database.namesOfAccounts;
            }
        }

        public static List<string> NamesOfFuelstations
        {
            get
            {
                if (Database.namesOfFuelstations.Count == 0)
                {
                    Database.namesOfFuelstations.Add("Tanken am Real");
                    Database.namesOfFuelstations.Add("Streit");
                    Database.namesOfFuelstations.Add("Dorst");
                    Database.namesOfFuelstations.Add("Aral");
                    Database.namesOfFuelstations.Add("Shell");
                    Database.namesOfFuelstations.Add("Esso");
                    Database.namesOfFuelstations.Add("BP");
                    Database.namesOfFuelstations.Add("bft");
                    Database.namesOfFuelstations.Add("TotalElfFina");
                    Database.namesOfFuelstations.Add("Avia");
                    Database.namesOfFuelstations.Add("Jet");
                    Database.namesOfFuelstations.Add("Agip");
                    Database.namesOfFuelstations.Add("BayWa");
                    Database.namesOfFuelstations.Add("OMV");
                    Database.namesOfFuelstations.Add("Tamoil/HEM");
                    Database.namesOfFuelstations.Add("Freie Tankstelle");
                    Database.namesOfFuelstations.Add("Sonstige");
                    Database.namesOfFuelstations.Add("Raiffeisen");
                    Database.namesOfFuelstations.Add("Orlen");
                    Database.namesOfFuelstations.Add("OIL!");
                    Database.namesOfFuelstations.Add("Q1");
                    Database.namesOfFuelstations.Add("Westfalen");

                }
                return Database.namesOfFuelstations;
            }
        }

        public static string LastMileometer
        {
            get
            {
                if (String.IsNullOrEmpty(Database.lastMileometer))
                {
                    Database.lastMileometer = "025555";
                    using (StreamReader fs = File.OpenText(Filenames.FilenameLastMileometer))
                    {
                        while (!fs.EndOfStream)
                        {
                            string line = fs.ReadLine().Trim();
                            if (!String.IsNullOrEmpty(line))
                            {
                                Database.lastMileometer = line;
                                break;
                            }
                        }
                    }
                }
                return Database.lastMileometer;

            }
        }

        public static List<string> NamesOfCategoriesEx
        {
            get
            {
                if (Database.namesOfCategoriesEx.Count == 0)
                {
                    Database.namesOfCategoriesEx = Helper.GetSubCatNames(0, Filenames.FilenameCategoryEx);
                }
                return Database.NamesOfCategoriesEx;
            }
        }
        public static List<string> NamesOfCategoriesIn
        {
            get
            {
                if (Database.namesOfCategoriesIn.Count == 0)
                {
                    Database.namesOfCategoriesIn = Helper.GetSubCatNames(0, Filenames.FilenameCategoryIn);
                }
                return Database.namesOfCategoriesIn;
            }
        }

        #endregion
        #endregion

        #region Singleton
        private Database() { }
        private static Database db = null;

        public static Database Db
        {
            get
            {
                if (db == null)
                    db = Load();
                return Database.db;
            }
        }
        #endregion

        public static void Init(string filename)
        {
            try
            {
                using (FileStream fs = File.Open(filename, FileMode.Open))
                {
                    if (xmlSer == null)
                        xmlSer = new XmlSerializer(typeof(Database));
                    object dsObj = xmlSer.Deserialize(fs);
                    Database.db = (Database)dsObj;
                }
            }
            catch
            {
                Database.db = new Database();
            }
        }

        /// <summary>
        /// Loads this instance.
        /// </summary>
        /// <returns></returns>
        private static Database Load()
        {
            Database db = null;
            try
            {
                using (FileStream fs = File.Open(Filenames.FilenameDatabase, FileMode.Open))
                {
                    if (xmlSer == null)
                        xmlSer = new XmlSerializer(typeof(Database));
                    object dsObj = xmlSer.Deserialize(fs);
                    db = (Database)dsObj;
                }
            }
            catch
            {
                db = new Database();
            }
            return db;
        }

        public void Save()
        {
            using (FileStream fs = File.Create(Filenames.FilenameDatabase))
            {
                if (xmlSer == null)
                    xmlSer = new XmlSerializer(typeof(Database));
                xmlSer.Serialize(fs, this);
            }
            using (StreamWriter sw = File.CreateText(Filenames.FilenameAccounts))
            {
                StringBuilder s = new StringBuilder();
                foreach (var item in this.Accounts)
                {
                    s.AppendLine(item.Name);
                }
                sw.Write(s.ToString());
            }

            File.Delete(Filenames.FilenameLastMileometer);
            using (StreamWriter sw = File.CreateText(Filenames.FilenameLastMileometer))
            {
                int max = (from cInfo in this.Fuels
                           select cInfo.Mileage).Max();

                max += 500; // Wie weit man halt mit einem Tank so kommt.

                sw.WriteLine(String.Format("{0:000000}", max));
            }
        }
    }
}
